﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using MugenMvvmToolkit.Annotations;
using MugenMvvmToolkit.Attributes;
using MugenMvvmToolkit.Infrastructure;
using MugenMvvmToolkit.Interfaces;
using MugenMvvmToolkit.Interfaces.ViewModels;
using MugenMvvmToolkit.Models;
using MugenMvvmToolkit.Utils;
#if TASKSUPPORT
using System.Threading.Tasks;
#endif

namespace MugenMvvmToolkit.ViewModels
{
    /// <summary>
    ///     Represents the view-model which has validation support.
    /// </summary>
    [BaseViewModel(Priority = 6)]
    public class ValidatableViewModel : ViewModelBase, IValidatableViewModel, IHandler<AsyncValidationMessage>, IHandler<DataErrorsChangedMessage>
    {
        #region Fields

#if !NODATAERROR
        private bool _noValidate;
#endif

        /// <summary>
        /// Gets the dictionary that contains mapping from an instance to validators.
        /// </summary>
        protected readonly Dictionary<object, List<IValidator>> InstanceToValidators;
        private readonly object _locker;
        private readonly object _validatingLocker;
        private readonly Dictionary<string, ICollection<string>> _propertiesMapping;
        private readonly HashSet<string> _ignoreProperties;

        private bool _isValidating;
        private bool _cyclicValidationDetectionEnabled;

        #endregion

        #region Constructors

        /// <summary>
        ///     Initializes a new instance of the <see cref="ValidatableViewModel" /> class.
        /// </summary>
        public ValidatableViewModel()
        {
            _locker = new object();
            _validatingLocker = new object();
            _propertiesMapping = new Dictionary<string, ICollection<string>>(MvvmUtilsInternalAdvanced.GetViewModelToModelProperties(ViewModelType));
            _ignoreProperties = new HashSet<string>(MvvmUtilsInternalAdvanced.GetIgnoreProperties(ViewModelType));
            InstanceToValidators = new Dictionary<object, List<IValidator>>();
            CyclicValidationDetectionEnabled = GlobalSettings.CyclicValidationDetectionEnabled;
        }

        #endregion

        #region Properties

        /// <summary>
        ///     Gets or sets value that responsible for checking the cyclic validation. 
        ///     If <c>true</c> view model throw an exception if the cyclic validation will be detected, otherwise <c>false</c>.
        /// </summary>
        protected bool CyclicValidationDetectionEnabled
        {
            get { return _cyclicValidationDetectionEnabled; }
            set
            {
                _cyclicValidationDetectionEnabled = value;
                if (!value)
                    _isValidating = false;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        ///     Adds the specified validator.
        /// </summary>
        /// <param name="instanceToValidate">The specified instance to validate.</param>
        public TValidator AddValidator<TValidator>(object instanceToValidate) where TValidator : IValidator
        {
            EnsureIsNotDisposed();
            Should.NotBeNull(instanceToValidate, "instanceToValidate");
            var validator = Get<TValidator>();
            validator.Initialize(CreateContext(instanceToValidate));
            AddValidator(validator);
            return validator;
        }

        /// <summary>
        ///     Clears errors for a property.
        /// </summary>
        /// <param name="propertyName">The name of the property</param>
        protected virtual void ClearErrorsInternal(string propertyName)
        {
            Validators.ForEach(validator => validator.ClearErrors(propertyName));
        }

        /// <summary>
        ///     Clears the all errors.
        /// </summary>
        protected virtual void ClearErrorsInternal()
        {
            Validators.ForEach(validator => validator.ClearErrors());
        }

        /// <summary>
        ///     Gets the validation errors for a specified property or for the entire entity.
        /// </summary>
        /// <returns>
        ///     The validation errors for the property or entity.
        /// </returns>
        /// <param name="propertyName">
        ///     The name of the property to retrieve validation errors for; or null or <see cref="F:System.String.Empty" />, to retrieve entity-level errors.
        /// </param>
        protected virtual IEnumerable GetErrorsInternal(string propertyName)
        {
            var listResults = new List<object>();
            foreach (IValidator validator in Validators)
            {
                IEnumerable enumerable = validator.GetErrors(propertyName);
                listResults.AddRange(enumerable.OfType<object>());
            }
            return listResults;
        }

        /// <summary>
        ///     Gets the all validation errors.
        /// </summary>
        /// <returns>
        ///     The validation errors.
        /// </returns>
        protected virtual IDictionary<string, IList<object>> GetAllErrorsInternal()
        {
            return MvvmExtensionsAdvanced.MergeDictionaries(Validators.Select(validator => validator.GetAllErrors()).ToArray());
        }

        /// <summary>
        ///     Adds the specified validator.
        /// </summary>
        /// <param name="validator">The specified validator.</param>
        protected virtual void AddValidatorInternal(IValidator validator)
        {
            if (!validator.IsInitialized)
                Thrower.ValidatorIsNotInitialized("validator");
            //To prevent recursive validation call.
            if (validator is ValidatableViewModelValidator && Equals(validator.Context.InstanceToValidate, this))
            {
                validator.Dispose();
                return;
            }

            List<IValidator> validators;
            InstanceToValidators.TryGetValue(validator.Context.InstanceToValidate, out validators);
            if (validators == null)
            {
                validators = new List<IValidator>();
                InstanceToValidators[validator.Context.InstanceToValidate] = validators;
            }
            validators.Add(validator);
#if !NONOTIFYDATAERROR
            validator.ErrorsChanged += ValidatorOnErrorsChanged;
#endif
            validator.Subscribe(this);
            validator.ValidateAll();
        }

        /// <summary>
        ///      Removes the specified validator.
        /// </summary>
        /// <param name="validator">The specified validator.</param>
        protected virtual bool RemoveValidatorInternal(IValidator validator)
        {
            if (!validator.IsInitialized)
                Thrower.ValidatorIsNotInitialized("validator");
            List<IValidator> validators;
            if (!InstanceToValidators.TryGetValue(validator.Context.InstanceToValidate, out validators) ||
                validators == null || !validators.Contains(validator))
                return false;
#if !NONOTIFYDATAERROR
            validator.ErrorsChanged -= ValidatorOnErrorsChanged;
#endif
            validator.Unsubscribe(this);
            validator.Dispose();
            return validators.Remove(validator);
        }

        /// <summary>
        ///     Adds the specified instance to validate.
        /// </summary>
        /// <param name="instanceToValidate">The specified instance to validate.</param>
        protected virtual void AddInstanceInternal(object instanceToValidate)
        {
            if (InstanceToValidators.ContainsKey(instanceToValidate))
                RemoveInstanceInternal(instanceToValidate);
            var validatorProvider = Get<IValidatorProvider>();
            var context = CreateContext(instanceToValidate);
            var validators = validatorProvider.GetValidators(context);
            foreach (var validator in validators)
                AddValidatorInternal(validator);
        }

        /// <summary>
        ///     Adds the specified instance to validate.
        /// </summary>
        /// <param name="instanceToValidate">The specified instance to validate.</param>
        protected virtual bool RemoveInstanceInternal(object instanceToValidate)
        {
            List<IValidator> validators;
            if (!InstanceToValidators.TryGetValue(instanceToValidate, out validators))
                return false;
            if (validators != null)
            {
                foreach (var validator in validators.ToArray())
                    RemoveValidatorInternal(validator);
            }
            return InstanceToValidators.Remove(instanceToValidate);
        }

        /// <summary>
        ///     Determines whether the current model is valid.
        /// </summary>
        /// <returns>
        ///     If <c>true</c> current model is valid, otherwise <c>false</c>.
        /// </returns>
        protected virtual bool IsValidInternal()
        {
            return Validators.All(validator => validator.IsValid());
        }

#if TASKSUPPORT
        /// <summary>
        ///     Updates information about errors in the specified instance.
        /// </summary>
        /// <param name="instanceToValidate">The specified instance to validate.</param>
        [SuppressTaskBusyHandler]
        protected virtual Task ValidateInstanceInternal(object instanceToValidate)
        {
            List<IValidator> list;
            if (!InstanceToValidators.TryGetValue(instanceToValidate, out list) || list.Count == 0)
                return MvvmUtils.TrueTaskResult;
            return MvvmExtensionsAdvanced.WhenAll(list.Select(validator => validator.ValidateAll()).ToArray());
        }

        /// <summary>
        ///     Updates information about errors in the specified property.
        /// </summary>
        /// <param name="propertyName">The specified property name.</param>
        [SuppressTaskBusyHandler]
        protected virtual Task ValidateInternal(string propertyName)
        {
            if (!Validators.Any())
                return MvvmUtils.TrueTaskResult;
            return MvvmExtensionsAdvanced.WhenAll(Validators.Select(validator => validator.Validate(propertyName)).ToArray());
        }

        /// <summary>
        ///     Updates information about all errors.
        /// </summary>
        [SuppressTaskBusyHandler]
        protected virtual Task ValidateAllInternal()
        {
            if (!Validators.Any())
                return MvvmUtils.TrueTaskResult;
            return MvvmExtensionsAdvanced.WhenAll(Validators.Select(validator => validator.ValidateAll()).ToArray());
        }
#else
        /// <summary>
        ///     Updates information about errors in the specified instance.
        /// </summary>
        /// <param name="instanceToValidate">The specified instance to validate.</param>
        protected virtual IOperationResult ValidateInstanceInternal(object instanceToValidate)
        {
            List<IValidator> list;
            if (!InstanceToValidators.TryGetValue(instanceToValidate, out list) || list.Count == 0)
                return MvvmUtils.TrueOperationResult;
            return MvvmExtensionsAdvanced.WhenAll(list.Select(validator => validator.ValidateAll()).ToArray());
        }

        /// <summary>
        ///     Updates information about errors in the specified property.
        /// </summary>
        /// <param name="propertyName">The specified property name.</param>
        protected virtual IOperationResult ValidateInternal(string propertyName)
        {
            if (!Validators.Any())
                return MvvmUtils.TrueOperationResult;
            return MvvmExtensionsAdvanced.WhenAll(Validators.Select(validator => validator.Validate(propertyName)).ToArray());
        }

        /// <summary>
        ///     Updates information about all errors.
        /// </summary>
        protected virtual IOperationResult ValidateAllInternal()
        {
            if (!Validators.Any())
                return MvvmUtils.TrueOperationResult;
            return MvvmExtensionsAdvanced.WhenAll(Validators.Select(validator => validator.ValidateAll()).ToArray());
        }
#endif
        /// <summary>
        /// Occurs when processing an asynchronous validation message.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="message">Information about event.</param>
        protected virtual void OnHandleAsyncValidationMessage(object sender, AsyncValidationMessage message)
        {
            if (message.IsEndOperation)
            {
                ((IHandler<EndBusyMessage>)this).Handle(this, new EndBusyMessage(message.Id));
                return;
            }
            ((IHandler<BeginBusyMessage>)this).Handle(this, new BeginBusyMessage(message.Id, GetValidationBusyMessage()));
        }

        /// <summary>
        /// Occurs when the validation errors have changed for a property or for the entire entity. 
        /// </summary>
        protected virtual void OnErrorsChanged(object sender, DataErrorsChangedMessage message)
        {
        }

        /// <summary>
        /// Occurs when any validation was processed with exception.
        /// </summary>
        protected virtual void OnValidationException(Exception exception)
        {
        }

        private object GetValidationBusyMessage()
        {
            if (IsInitialized)
                return Settings.ValidationBusyMessage;
            return GlobalSettings.DefaultViewModelSettings != null
                ? GlobalSettings.DefaultViewModelSettings.ValidationBusyMessage
                : string.Empty;
        }

        private void BeginValidation(string property)
        {
            if (_isValidating && CyclicValidationDetectionEnabled)
                Thrower.CyclicValidation(property);
            _isValidating = true;
        }

        #endregion

        #region Implementation of IDataErrorInfo

#if !NODATAERROR
        /// <summary>
        ///     Gets the error message for the property with the given name.
        /// </summary>
        /// <returns>
        ///     The error message for the property. The default is an empty string ("").
        /// </returns>
        /// <param name="columnName">
        ///     The name of the property whose error message to get.
        /// </param>
        string IDataErrorInfo.this[string columnName]
        {
            get
            {
                if (!_noValidate)
                {
                    Validate(columnName).WithTaskExceptionHandler(this);
                }
                object error = GetErrors(columnName).OfType<object>().FirstOrDefault(o => o != null);
                if (error == null)
                    return null;
                return error.ToString();
            }
        }

        /// <summary>
        ///     Gets an error message indicating what is wrong with this object.
        /// </summary>
        /// <returns>
        ///     An error message indicating what is wrong with this object. The default is an empty string ("").
        /// </returns>
        string IDataErrorInfo.Error
        {
            get
            {
                var stB = new StringBuilder();
                IEnumerable enumerable = GetErrors(string.Empty);
                foreach (var value in enumerable)
                {
                    if (value == null) continue;
                    stB.AppendLine(value.ToString());
                }
                return stB.ToString();
            }
        }
#endif
        #endregion

        #region Implementation of IValidatableViewModel

        /// <summary>
        ///     Gets the collection of validators.
        /// </summary>
        public IEnumerable<IValidator> Validators
        {
            get { return InstanceToValidators.Values.SelectMany(list => list); }
        }

        /// <summary>
        ///     Gets the mapping of model properties.
        ///   <example>
        ///     <code>
        ///       <![CDATA[
        ///        PropertiesMapping.Add("ModelProperty", new[]{"ViewModelProperty"});
        ///       ]]>
        ///     </code>
        ///   </example>
        /// </summary>
        public IDictionary<string, ICollection<string>> PropertiesMapping
        {
            get { return _propertiesMapping; }
        }

        /// <summary>
        ///     Gets the list of properties that will not be validated.
        /// </summary>
        public ICollection<string> IgnoreProperties
        {
            get { return _ignoreProperties; }
        }

        /// <summary>
        /// Creates an instance of <see cref="IValidatorContext"/>.
        /// </summary>
        /// <param name="instanceToValidate">The specified instance to validate.</param>
        /// <returns>An instance of <see cref="IValidatorContext"/>.</returns>
        public virtual IValidatorContext CreateContext(object instanceToValidate)
        {
            EnsureIsNotDisposed();
            Should.NotBeNull(instanceToValidate, "instanceToValidate");
            IDictionary<object, object> dictionary = null;
            var factory = Settings.MetadataFactory;
            if (factory != null)
                dictionary = factory();
            return new ValidatorContext(instanceToValidate, PropertiesMapping, IgnoreProperties, dictionary, IocAdapter);
        }

        /// <summary>
        ///     Adds the specified validator.
        /// </summary>
        /// <param name="validator">The specified validator.</param>
        public void AddValidator(IValidator validator)
        {
            EnsureIsNotDisposed();
            Should.NotBeNull(validator, "validator");
            Should.NotBeNull(validator.Context, "validator.Context");

            using (DeadLockDetector.Lock(_locker))
            {
                AddValidatorInternal(validator);
            }
        }

        /// <summary>
        ///      Removes the specified validator.
        /// </summary>
        /// <param name="validator">The specified validator.</param>
        public bool RemoveValidator(IValidator validator)
        {
            EnsureIsNotDisposed();
            Should.NotBeNull(validator, "validator");
            Should.NotBeNull(validator.Context, "validator.Context");

            using (DeadLockDetector.Lock(_locker))
            {
                return RemoveValidatorInternal(validator);
            }
        }

        /// <summary>
        ///     Adds the specified instance to validate.
        /// </summary>
        /// <param name="instanceToValidate">The specified instance to validate.</param>
        public void AddInstance(object instanceToValidate)
        {
            EnsureIsNotDisposed();
            Should.NotBeNull(instanceToValidate, "instanceToValidate");
            using (DeadLockDetector.Lock(_locker))
            {
                AddInstanceInternal(instanceToValidate);
            }
        }

        /// <summary>
        ///     Removes the specified instance to validate.
        /// </summary>
        /// <param name="instanceToValidate">The specified instance to validate.</param>
        public bool RemoveInstance(object instanceToValidate)
        {
            EnsureIsNotDisposed();
            Should.NotBeNull(instanceToValidate, "instanceToValidate");
            using (DeadLockDetector.Lock(_locker))
            {
                return RemoveInstanceInternal(instanceToValidate);
            }
        }

#if TASKSUPPORT
        /// <summary>
        ///     Updates information about errors in the specified instance.
        /// </summary>
        /// <param name="instanceToValidate">The specified instance to validate.</param>
        [SuppressTaskBusyHandler]
        public Task ValidateInstance(object instanceToValidate)
        {
            EnsureIsNotDisposed();
            Should.NotBeNull(instanceToValidate, "instanceToValidate");
            Task task;
            using (DeadLockDetector.Lock(_locker))
            {
                task = ValidateInstanceInternal(instanceToValidate);
            }
            return task.ContinueWith(OnValidated, task.GetContinuationOptions());
        }

        /// <summary>
        ///     Updates information about errors in the specified property.
        /// </summary>
        /// <param name="propertyName">The specified property name.</param>
        [SuppressTaskBusyHandler]
        public Task Validate(string propertyName)
        {
            Should.NotBeNull(propertyName, "propertyName");
            Task task;
            using (DeadLockDetector.Lock(_locker))
            {
                task = ValidateInternal(propertyName);
            }
            return task.ContinueWith(OnValidated, task.GetContinuationOptions());
        }

        /// <summary>
        ///     Updates information about all errors.
        /// </summary>
        [SuppressTaskBusyHandler]
        public Task ValidateAll()
        {
            EnsureIsNotDisposed();
            Task task;
            using (DeadLockDetector.Lock(_locker))
            {
                task = ValidateAllInternal();
            }
            return task.ContinueWith(OnValidated, task.GetContinuationOptions());
        }

        private void OnValidated(Task task)
        {
            if (task.IsFaulted || task.IsCanceled)
                OnValidationException(task.Exception);
        }
#else
        /// <summary>
        ///     Updates information about errors in the specified instance.
        /// </summary>
        /// <param name="instanceToValidate">The specified instance to validate.</param>        
        public IOperationResult ValidateInstance(object instanceToValidate)
        {
            EnsureIsNotDisposed();
            Should.NotBeNull(instanceToValidate, "instanceToValidate");
            IOperationResult result;
            using (DeadLockDetector.Lock(_locker))
            {
                result = ValidateInstanceInternal(instanceToValidate);
            }
            result.BeginWait(OnValidated);
            return result;
        }

        /// <summary>
        ///     Updates information about errors in the specified property.
        /// </summary>
        /// <param name="propertyName">The specified property name.</param>        
        public IOperationResult Validate(string propertyName)
        {
            Should.NotBeNull(propertyName, "propertyName");
            IOperationResult result;
            using (DeadLockDetector.Lock(_locker))
            {
                result = ValidateInternal(propertyName);
            }
            result.BeginWait(OnValidated);
            return result;
        }

        /// <summary>
        ///     Updates information about all errors.
        /// </summary>
        public IOperationResult ValidateAll()
        {
            EnsureIsNotDisposed();
            IOperationResult result;
            using (DeadLockDetector.Lock(_locker))
            {
                result = ValidateAllInternal();
            }
            result.BeginWait(OnValidated);
            return result;
        }

        private void OnValidated(IOperationResult operationResult)
        {
            if (operationResult.IsFaulted)
                OnValidationException(operationResult.Exception);
        }
#endif
        /// <summary>
        ///     Gets the validation errors for a specified property or for the entire entity.
        /// </summary>
        /// <returns>
        ///     The validation errors for the property or entity.
        /// </returns>
        /// <param name="propertyName">
        ///     The name of the property to retrieve validation errors for; or null or <see cref="F:System.String.Empty" />, to retrieve entity-level errors.
        /// </param>
        public IEnumerable GetErrors(string propertyName)
        {
            using (DeadLockDetector.Lock(_locker))
            {
                return GetErrorsInternal(propertyName);
            }
        }

        /// <summary>
        ///     Gets the all validation errors.
        /// </summary>
        /// <returns>
        ///     The validation errors.
        /// </returns>
        public IDictionary<string, IList<object>> GetAllErrors()
        {
            using (DeadLockDetector.Lock(_locker))
            {
                return GetAllErrorsInternal();
            }
        }

        /// <summary>
        ///     Clears errors for a property.
        /// </summary>
        /// <param name="propertyName">The name of the property</param>
        public void ClearErrors(string propertyName)
        {
            Should.NotBeNull(propertyName, "propertyName");
            using (DeadLockDetector.Lock(_locker))
            {
                ClearErrorsInternal(propertyName);
            }
        }

        /// <summary>
        ///     Clears the all errors.
        /// </summary>
        public void ClearErrors()
        {
            using (DeadLockDetector.Lock(_locker))
            {
                ClearErrorsInternal();
            }
        }

        /// <summary>
        ///     Determines whether the current view model is valid.
        /// </summary>
        /// <returns>
        ///     If <c>true</c> current view model is valid, otherwise <c>false</c>.
        /// </returns>
        public bool IsValid()
        {
            using (DeadLockDetector.Lock(_locker))
            {
                return IsValidInternal();
            }
        }

        /// <summary>
        ///     Handles the message.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="message">Information about event.</param>
        void IHandler<AsyncValidationMessage>.Handle(object sender, AsyncValidationMessage message)
        {
            OnHandleAsyncValidationMessage(sender, message);
        }

        /// <summary>
        ///     Handles the message.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="message">Information about event.</param>
        void IHandler<DataErrorsChangedMessage>.Handle(object sender, DataErrorsChangedMessage message)
        {
            if (CyclicValidationDetectionEnabled)
            {
                using (DeadLockDetector.Lock(_validatingLocker))
                using (new ActionToken(o => ((ValidatableViewModel)o)._isValidating = false, this))
                {
                    BeginValidation(message.PropertyName);
                    OnErrorsChanged(sender, message);
                }
            }
            else
            {
                OnErrorsChanged(sender, message);
            }
#if !NODATAERROR
            if (!message.IsAsyncValidate) return;
            ThreadManager.InvokeInUi(() =>
            {
                try
                {
                    _noValidate = true;
                    OnPropertyChanged(message.PropertyName);
                }
                finally
                {
                    _noValidate = false;
                }
            });
#endif
        }

        #endregion

        #region Implementation of INotifyDataErrorInfo

#if !NONOTIFYDATAERROR
        /// <summary>
        /// Gets a value that indicates whether the entity has validation errors. 
        /// </summary>
        /// <returns>
        /// true if the entity currently has validation errors; otherwise, false.
        /// </returns>
        bool INotifyDataErrorInfo.HasErrors
        {
            get { return !IsValid(); }
        }

        /// <summary>
        /// Occurs when the validation errors have changed for a property or for the entire entity. 
        /// </summary>
        public virtual event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        /// <summary>
        ///     Raises this object's ErrorsChangedChanged event.
        /// </summary>
        /// <param name="args">The event args.</param>
        protected void OnErrorsChangedEvent(DataErrorsChangedEventArgs args)
        {
            EventHandler<DataErrorsChangedEventArgs> handler = ErrorsChanged;
            if (handler == null) return;
            Settings.ErrorsChangeExecutionMode.Invoke(ThreadManager, () => handler(this, args));
        }

        private void ValidatorOnErrorsChanged(object sender, DataErrorsChangedEventArgs dataErrorsChangedEventArgs)
        {
            OnErrorsChangedEvent(dataErrorsChangedEventArgs);
        }
#endif

        #endregion

        #region Overrides of ViewModelBase

        /// <summary>
        ///     Occurs after the initialization of the current <see cref="ViewModelBase" />.
        /// </summary>
        internal override void OnInitializedInternal()
        {
            AddInstance(this);
        }

        /// <summary>
        ///     Occurs after current view model disposed, use for clear resource and event listeners(Internal only).
        /// </summary>
        internal override void OnDisposeInternal(bool disposing)
        {
            if (disposing)
            {
                KeyValuePair<object, List<IValidator>>[] keyValuePairs;
                using (DeadLockDetector.Lock(_locker))
                    keyValuePairs = InstanceToValidators.ToArray();

                foreach (var instanceToValidator in keyValuePairs)
                {
                    RemoveInstance(instanceToValidator.Key);
                }

#if !NONOTIFYDATAERROR
                var errorsChanged = ErrorsChanged;
                if (errorsChanged != null)
                {
                    foreach (EventHandler<DataErrorsChangedEventArgs> @delegate in errorsChanged.GetInvocationList())
                        ErrorsChanged -= @delegate;
                }
#endif
            }
            base.OnDisposeInternal(disposing);
        }

        #endregion
    }
}